using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Data;
using System.Data.Entity.Infrastructure;
using ShopPowerTemplate.Services.Properties;
using ShopPowerTemplate.Entities;

namespace ShopPowerTemplate.Services
{
    public class CustomerServiceBase : Service
    {
		public CustomerServiceBase(IEntitiesDB entitiesDB) : base(entitiesDB) { }
		
        public virtual Int32 Add(Customer customer)
        {
            EntitiesDB.CustomerSet.Add(customer);
            EntitiesDB.SaveChanges();
            return customer.Id;
        }

        public virtual void Change(Customer customer)
        {
		    EntitiesDB.Entry(customer).State = EntityState.Modified;

            EntitiesDB.SaveChanges();
        }
		
		public virtual void Remove(int id)
        {
			Customer customer = Find(id);
            try
            {
                EntitiesDB.CustomerSet.Remove(customer);
                EntitiesDB.SaveChanges();
            }
            catch (DbUpdateException)
            {
                throw new RemoveException(string.Format(Resources.RemoveException, customer.ToString()));
            }
        }

        public virtual void Remove(Customer customer)
        {
			Remove(customer.Id);
        }        

        public virtual Customer Find(int id)
        {
			Customer customer = 
				EntitiesDB.CustomerSet
					.Include("Reviews")
					.Include("Orders")
					.Include("Addresses")
					.FirstOrDefault(x => x.Id == id);
			return customer;
        }

        public virtual List<Customer> FindAll()
        {
            return EntitiesDB.CustomerSet.OrderBy(x => x.SessionId).ToList();
        }
		
		public virtual List<Customer> Search(string searchValue)
        {
            return Search(searchValue, string.Empty, true, 0, 0);
        }

        public virtual List<Customer> Search(string searchValue, int pageIndex, int pageSize)
        {
            return Search(searchValue, string.Empty, true, pageIndex, pageSize);
        }

        public virtual List<Customer> Search(string searchValue, string orderBy)
        {
            return Search(searchValue, orderBy, true, 0, 0);
        }

        public virtual List<Customer> Search(string searchValue, string orderBy, int pageIndex, int pageSize)
        {
            return Search(searchValue, orderBy, true, pageIndex, pageSize);
        }

        public virtual List<Customer> Search(string searchValue, string orderBy = "", bool ascending = true, int pageIndex = 0, int pageSize = 10)
        {
            IQueryable<Customer> query = EntitiesDB.CustomerSet.Where(x => string.IsNullOrEmpty(searchValue) || x.FirstName.Contains(searchValue)
				|| x.LastName.Contains(searchValue)
				|| x.Email.Contains(searchValue)
				|| x.SessionId.Contains(searchValue));
			
			if(orderBy == string.Empty)
				orderBy = "Id";			
			
			query = ascending ? query.OrderBy(orderBy) : query.OrderByDescending(orderBy);

            if (pageSize > 0)
                query = query.Skip(pageSize * pageIndex).Take(pageSize);

            return query.ToList();
        }
		
		public virtual List<Customer> Search(Expression<Func<Customer, bool>> searchCriteria, string orderBy = "", bool ascending = true, int pageIndex = 0, int pageSize=10)
        {
            IQueryable<Customer> query = EntitiesDB.CustomerSet.Where(searchCriteria);
            
			if(orderBy == string.Empty)
				orderBy = "Id";			
			
			query = ascending ? query.OrderBy(orderBy) : query.OrderByDescending(orderBy);

            if (pageSize > 0)
                query = query.Skip(pageSize * pageIndex).Take(pageSize);

            return query.ToList();
        }

        public virtual int SearchCount(string searchValue)
        {
            return EntitiesDB.CustomerSet.Where(x => string.IsNullOrEmpty(searchValue) || x.FirstName.Contains(searchValue)
				|| x.LastName.Contains(searchValue)
				|| x.Email.Contains(searchValue)
				|| x.SessionId.Contains(searchValue)).Count();
        }
		
		public virtual List<Customer> FindAvailableCustomerList<TKey>(List<Customer> notAvailableList, string searchValue, System.Linq.Expressions.Expression<Func<Customer, TKey>> orderBy, bool ascending, int pageIndex, int pageSize)
        {
            IEnumerable<int> notAvailableIDList = notAvailableList.Select(na => na.Id);
            IQueryable<Customer> query = EntitiesDB.CustomerSet.Where(a => !notAvailableIDList.Any(id => id == a.Id)).Where(x => string.IsNullOrEmpty(searchValue) || x.FirstName.Contains(searchValue)
				|| x.LastName.Contains(searchValue)
				|| x.Email.Contains(searchValue)
				|| x.SessionId.Contains(searchValue));

			query = ascending ? query.OrderBy(orderBy) : query.OrderByDescending(orderBy);

            if (pageSize > 0)
                query = query.Skip(pageSize * pageIndex).Take(pageSize);

            return query.ToList();
        }

        public virtual int FindAvailableCustomerListCount(List<Customer> notAvailableList, string searchValue)
        {
            IEnumerable<int> notAvailableIDList = notAvailableList.Select(na => na.Id);
            return EntitiesDB.CustomerSet.Where(a => !notAvailableIDList.Any(id => id == a.Id)).Where(x => string.IsNullOrEmpty(searchValue) || x.FirstName.Contains(searchValue)
				|| x.LastName.Contains(searchValue)
				|| x.Email.Contains(searchValue)
				|| x.SessionId.Contains(searchValue)).Count();
        }
	
		public virtual void AddReviews(Customer customer, Review reviews)
        {
			customer = Find(customer.Id);
            reviews.Customer = customer;
            customer.Reviews.Add(reviews);
            reviews.Product = EntitiesDB.EntryWithState(reviews.Product, EntityState.Unchanged);

            Change(customer);
        }
		
		public virtual void RemoveReviews(Customer customer, Review reviews)
        {
            customer.Reviews.Remove(reviews);
			EntitiesDB.ReviewSet.Remove(reviews);			
            Change(customer);
        }

		public virtual void AddOrders(Customer customer, Order orders)
        {
			customer = Find(customer.Id);
            orders.Customer = customer;
            customer.Orders.Add(orders);
            orders.OrderState = EntitiesDB.EntryWithState(orders.OrderState, EntityState.Unchanged);

            Change(customer);
        }
		
		public virtual void RemoveOrders(Customer customer, Order orders)
        {
            customer.Orders.Remove(orders);
			EntitiesDB.OrderSet.Remove(orders);			
            Change(customer);
        }

		public virtual void AddAddresses(Customer customer, Address addresses)
        {
			customer = Find(customer.Id);
            addresses.Customer = customer;
            customer.Addresses.Add(addresses);

            Change(customer);
        }
		
		public virtual void RemoveAddresses(Customer customer, Address addresses)
        {
            customer.Addresses.Remove(addresses);
			EntitiesDB.AddressSet.Remove(addresses);			
            Change(customer);
        }

    }
}
